package com.zeratul.common.event.domain;

import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.zeratul.common.event.enums.Qos;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 事件实体
 */
@Slf4j
@Data
@Accessors(chain = true)
public class ZtEvent<T> implements Serializable {

    /**
     * 消息的唯一标识
     */
    private String id;

    /**
     * 可靠性等级
     */
    private Qos qos;

    /**
     * 事件主题
     */
    private String topic;

    /**
     * 事件内容
     */
    private T msg;

    /**
     * 延迟的时间 单位ms
     */
    private Long delayTime;

    /**
     * 过期时间
     */
    private Long expireTime;

    /**
     * 发送时间
     */
    private Date sendTime;

    /**
     * 接收时间
     */
    private Date recvTime;

    /**
     * 拓展属性
     */
    private Map<String, Object> extra = new HashMap<>();

    /**
     * MDC日志相关属性
     */
    private Map<String, String> mdc;

    /**
     * 全局上下文集合
     */
    private Map<String, Object> traceContext;

    /**
     * 添加拓展属性
     */
    public ZtEvent<T> addExtra(String key, Object value) {
        if (ObjectUtil.isNull(extra)) {
            extra = new HashMap<>();
        }
        extra.put(key, value);
        return this;
    }

    /**
     * 添加多个拓展属性
     */
    public ZtEvent<T> addExtra(Map<String, Object> extras) {
        if (ObjectUtil.isNull(extra)) {
            extra = new HashMap<>();
        }
        extra.putAll(extras);
        return this;
    }

    /**
     * 获取拓展属性
     */
    @SuppressWarnings("unchecked")
    public <R> R getExtra(String key) {
        if (ObjectUtil.isEmpty(extra)) {
            return null;
        }
        return (R) extra.get(key);
    }

    /**
     * 事件的延迟时间，单位ms
     */
    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
    public long getDelayMsTime() {
        if (!ObjectUtil.isAllNotEmpty(sendTime, recvTime)) {
            return 0L;
        }

        return Math.abs(recvTime.getTime() - sendTime.getTime());
    }

    /**
     * 判断事件是否过期
     */
    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
    public boolean isExpire() {
        if (ObjectUtil.isEmpty(expireTime) || expireTime <= 0L) {
            return false;
        }
        return System.currentTimeMillis() - sendTime.getTime() > expireTime;
    }
}